package tq.com.tqcom.net;

import android.os.Handler;
import android.os.Looper;
import android.util.Log;

import org.json.JSONObject;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

import static tq.com.tqcom.net.TQNetResult.TQ_NET_ERROR;

public class TQNetClient {
    static private TQNetClient shareClient = new TQNetClient();

    private String baseUrl;
    private String authToken;

    private Handler mHandler = new Handler(Looper.getMainLooper());
    private OkHttpClient mOkHttpClient;

    static public TQNetClient getShareClient(){
        return shareClient;
    }

    public void setBaseUrl(String url){
        if(url == null || url.length() == 0) return;
        if(url.endsWith("/")){
            baseUrl = url.substring(0, url.length() - 1);
        }else {
            baseUrl = url;
        }
    }

    public String fullUrl(String path){
        return String.format("%s%s", baseUrl, path);
    }

    private OkHttpClient getOkHttpClient(){
        if(mOkHttpClient == null){
            mOkHttpClient = new OkHttpClient.Builder()
                    .connectTimeout(30, TimeUnit.SECONDS)
                    .readTimeout(30, TimeUnit.SECONDS)
                    .build();
        }
        return mOkHttpClient;
    }
    public void setAuthToken(String pToken){
        authToken = pToken;
    }
    private void addToken(Request.Builder pBuilder){
        if(authToken != null && authToken.length() > 0){
            pBuilder.addHeader("X-Auth-Token", authToken);
        }else{
            pBuilder.removeHeader("X-Auth-Token");
        }
    }

    public void get(String url, Map<String, String> param, INetCallback pNetCallback){
        StringBuilder fullUrl = new StringBuilder(fullUrl(url));

        if(param != null){
            for (Map.Entry<String, String> lEntry:
                    param.entrySet()) {
                if(fullUrl.indexOf("?") != -1){
                    fullUrl.append(String.format("?%s=%s", lEntry.getKey(), lEntry.getValue()));
                }else{
                    fullUrl.append(String.format("&%s=%s", lEntry.getKey(), lEntry.getValue()));
                }
            }
        }

        try{
            Request.Builder lRequest = new Request.Builder()
                    .url(fullUrl.toString())
                    .get();

            addToken(lRequest);
            getOkHttpClient().newCall(lRequest.build()).enqueue(new NetCallback(url, pNetCallback));
        }catch (Exception pE){
            pE.printStackTrace();
        }
    }

    public void post(String url, Map<String, Object> param, INetCallback pNetCallback){
        String full = fullUrl(url);

        JSONObject lObject = new JSONObject(param);
        String body = lObject.toString();

        MediaType lMediaType = MediaType.parse("application/json; charset=utf-8");
        RequestBody lBody = RequestBody.create(lMediaType, body);

        Request.Builder lBuilder = new Request.Builder()
                .post(lBody)
                .url(full);
        addToken(lBuilder);

        getOkHttpClient().newCall(lBuilder.build()).enqueue(new NetCallback(url, pNetCallback));
    }


    public void post(String url , String file, String desc,  INetCallback pCallback){
        String full = fullUrl(url);

        MediaType lMediaType = MediaType.parse("application/octet-stream");
        File lFile = new File(file);

        String type = getExtensionName(lFile.getName());
        MultipartBody.Builder lBuilder = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("file_type", type)
                .addFormDataPart("file", lFile.getName(), RequestBody.create(lMediaType, lFile));

        if(desc != null && desc.length() > 0){
            lBuilder.addFormDataPart("file_tag", desc);
        }

        Request.Builder lBuilder1 = new Request.Builder()
                .url(full)
                .post(lBuilder.build());
        addToken(lBuilder1);

        getOkHttpClient().newCall(lBuilder1.build()).enqueue(new NetCallback(url, pCallback));

    }

    public static String getExtensionName(String filename) {
        if ((filename != null) && (filename.length() > 0)) {
            int dot = filename.lastIndexOf('.');
            if ((dot >-1) && (dot < (filename.length() - 1))) {
                return filename.substring(dot + 1);
            }
        }
        return filename;
    }

    class NetCallback implements Callback{
        private String requestUrl;
        private INetCallback mINetCallback;

        public NetCallback(String url, INetCallback pCallback){
            requestUrl = url;
            mINetCallback = pCallback;
        }
        @Override
        public void onFailure(Call call, IOException e) {
            Log.d(TAG, "onFailure: ");

            e.printStackTrace();

            TQNetResult ret = TQNetResult.errMsg(-1, "网络报错，请稍后重试");
            ret.requestUrl = requestUrl;

            dispatchMain(ret, mINetCallback);
        }

        @Override
        public void onResponse(Call call, Response response) {
            Log.d(TAG, "onResponse: ");
            try {
                String body = response.body().string();
                JSONObject lObject = new JSONObject(body);
                TQNetResult lNetResult = new TQNetResult(lObject);

                dispatchMain(lNetResult, mINetCallback);
            }catch (Exception pE){
                pE.printStackTrace();

                TQNetResult ret = TQNetResult.errMsg(-1, "服务器返回错误");
                ret.requestUrl = requestUrl;

                dispatchMain(ret, mINetCallback);
            }
        }
    }

    private void dispatchMain(final TQNetResult pNetResult, final INetCallback pCallback){
        if(pCallback == null) return;

        mHandler.post(new Runnable() {
            @Override
            public void run() {
                pCallback.result(pNetResult);
            }
        });
    }


    private String TAG = getClass().getName();
}
